<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>宏定义规范</title>
        
        


        <!-- Custom HTML head -->
        


        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        
        <link rel="icon" href="favicon.svg">
        
        
        <link rel="shortcut icon" href="favicon.png">
        
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        
        <link rel="stylesheet" href="fonts/fonts.css">
        

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        
        <link rel="stylesheet" href="theme/reference.css">
        

        
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="翻译说明.html">翻译说明</a></li><li class="chapter-item expanded affix "><a href="introduction.html">介绍</a></li><li class="chapter-item expanded "><a href="notation.html"><strong aria-hidden="true">1.</strong> 表义符</a></li><li class="chapter-item expanded "><a href="lexical-structure.html"><strong aria-hidden="true">2.</strong> 词法结构</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="input-format.html"><strong aria-hidden="true">2.1.</strong> 输入格式</a></li><li class="chapter-item expanded "><a href="keywords.html"><strong aria-hidden="true">2.2.</strong> 关键字</a></li><li class="chapter-item expanded "><a href="identifiers.html"><strong aria-hidden="true">2.3.</strong> 标识符</a></li><li class="chapter-item expanded "><a href="comments.html"><strong aria-hidden="true">2.4.</strong> 注释</a></li><li class="chapter-item expanded "><a href="whitespace.html"><strong aria-hidden="true">2.5.</strong> 空白符</a></li><li class="chapter-item expanded "><a href="tokens.html"><strong aria-hidden="true">2.6.</strong> token</a></li></ol></li><li class="chapter-item expanded "><a href="macros.html"><strong aria-hidden="true">3.</strong> 宏</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="macros-by-example.html"><strong aria-hidden="true">3.1.</strong> 声明宏</a></li><li class="chapter-item expanded "><a href="procedural-macros.html"><strong aria-hidden="true">3.2.</strong> 过程宏</a></li></ol></li><li class="chapter-item expanded "><a href="crates-and-source-files.html"><strong aria-hidden="true">4.</strong> crate 和源文件</a></li><li class="chapter-item expanded "><a href="conditional-compilation.html"><strong aria-hidden="true">5.</strong> 条件编译</a></li><li class="chapter-item expanded "><a href="items.html"><strong aria-hidden="true">6.</strong> 程序项</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="items/modules.html"><strong aria-hidden="true">6.1.</strong> 模块</a></li><li class="chapter-item expanded "><a href="items/extern-crates.html"><strong aria-hidden="true">6.2.</strong> 外部crate</a></li><li class="chapter-item expanded "><a href="items/use-declarations.html"><strong aria-hidden="true">6.3.</strong> use声明</a></li><li class="chapter-item expanded "><a href="items/functions.html"><strong aria-hidden="true">6.4.</strong> 函数</a></li><li class="chapter-item expanded "><a href="items/type-aliases.html"><strong aria-hidden="true">6.5.</strong> 类型别名</a></li><li class="chapter-item expanded "><a href="items/structs.html"><strong aria-hidden="true">6.6.</strong> 结构体</a></li><li class="chapter-item expanded "><a href="items/enumerations.html"><strong aria-hidden="true">6.7.</strong> 枚举</a></li><li class="chapter-item expanded "><a href="items/unions.html"><strong aria-hidden="true">6.8.</strong> 联合体</a></li><li class="chapter-item expanded "><a href="items/constant-items.html"><strong aria-hidden="true">6.9.</strong> 常量项</a></li><li class="chapter-item expanded "><a href="items/static-items.html"><strong aria-hidden="true">6.10.</strong> 静态项</a></li><li class="chapter-item expanded "><a href="items/traits.html"><strong aria-hidden="true">6.11.</strong> trait</a></li><li class="chapter-item expanded "><a href="items/implementations.html"><strong aria-hidden="true">6.12.</strong> 实现</a></li><li class="chapter-item expanded "><a href="items/external-blocks.html"><strong aria-hidden="true">6.13.</strong> 外部块</a></li><li class="chapter-item expanded "><a href="items/generics.html"><strong aria-hidden="true">6.14.</strong> 泛型参数</a></li><li class="chapter-item expanded "><a href="items/associated-items.html"><strong aria-hidden="true">6.15.</strong> 关联程序项</a></li></ol></li><li class="chapter-item expanded "><a href="attributes.html"><strong aria-hidden="true">7.</strong> 属性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="attributes/testing.html"><strong aria-hidden="true">7.1.</strong> 测试</a></li><li class="chapter-item expanded "><a href="attributes/derive.html"><strong aria-hidden="true">7.2.</strong> 派生</a></li><li class="chapter-item expanded "><a href="attributes/diagnostics.html"><strong aria-hidden="true">7.3.</strong> 诊断</a></li><li class="chapter-item expanded "><a href="attributes/codegen.html"><strong aria-hidden="true">7.4.</strong> 代码生成</a></li><li class="chapter-item expanded "><a href="attributes/limits.html"><strong aria-hidden="true">7.5.</strong> 极限值设置</a></li><li class="chapter-item expanded "><a href="attributes/type_system.html"><strong aria-hidden="true">7.6.</strong> 类型系统</a></li></ol></li><li class="chapter-item expanded "><a href="statements-and-expressions.html"><strong aria-hidden="true">8.</strong> 语句和表达式</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="statements.html"><strong aria-hidden="true">8.1.</strong> 语句</a></li><li class="chapter-item expanded "><a href="expressions.html"><strong aria-hidden="true">8.2.</strong> 表达式</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="expressions/literal-expr.html"><strong aria-hidden="true">8.2.1.</strong> 字面量表达式</a></li><li class="chapter-item expanded "><a href="expressions/path-expr.html"><strong aria-hidden="true">8.2.2.</strong> 路径表达式</a></li><li class="chapter-item expanded "><a href="expressions/block-expr.html"><strong aria-hidden="true">8.2.3.</strong> 块表达式</a></li><li class="chapter-item expanded "><a href="expressions/operator-expr.html"><strong aria-hidden="true">8.2.4.</strong> 运算符表达式</a></li><li class="chapter-item expanded "><a href="expressions/grouped-expr.html"><strong aria-hidden="true">8.2.5.</strong> 分组表达式</a></li><li class="chapter-item expanded "><a href="expressions/array-expr.html"><strong aria-hidden="true">8.2.6.</strong> 数组和索引表达式</a></li><li class="chapter-item expanded "><a href="expressions/tuple-expr.html"><strong aria-hidden="true">8.2.7.</strong> 元组和索引表达式</a></li><li class="chapter-item expanded "><a href="expressions/struct-expr.html"><strong aria-hidden="true">8.2.8.</strong> 结构体表达式</a></li><li class="chapter-item expanded "><a href="expressions/call-expr.html"><strong aria-hidden="true">8.2.9.</strong> 调用表达式</a></li><li class="chapter-item expanded "><a href="expressions/method-call-expr.html"><strong aria-hidden="true">8.2.10.</strong> 方法调用表达式</a></li><li class="chapter-item expanded "><a href="expressions/field-expr.html"><strong aria-hidden="true">8.2.11.</strong> 字段访问表达式</a></li><li class="chapter-item expanded "><a href="expressions/closure-expr.html"><strong aria-hidden="true">8.2.12.</strong> 闭包表达式</a></li><li class="chapter-item expanded "><a href="expressions/loop-expr.html"><strong aria-hidden="true">8.2.13.</strong> 循环表达式</a></li><li class="chapter-item expanded "><a href="expressions/range-expr.html"><strong aria-hidden="true">8.2.14.</strong> 区间表达式</a></li><li class="chapter-item expanded "><a href="expressions/if-expr.html"><strong aria-hidden="true">8.2.15.</strong> if 和 if let 表达式</a></li><li class="chapter-item expanded "><a href="expressions/match-expr.html"><strong aria-hidden="true">8.2.16.</strong> 匹配表达式</a></li><li class="chapter-item expanded "><a href="expressions/return-expr.html"><strong aria-hidden="true">8.2.17.</strong> 返回表达式</a></li><li class="chapter-item expanded "><a href="expressions/await-expr.html"><strong aria-hidden="true">8.2.18.</strong> 等待(await)表达式</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="patterns.html"><strong aria-hidden="true">9.</strong> 模式</a></li><li class="chapter-item expanded "><a href="type-system.html"><strong aria-hidden="true">10.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="types.html"><strong aria-hidden="true">10.1.</strong> 类型</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="types/boolean.html"><strong aria-hidden="true">10.1.1.</strong> 布尔型</a></li><li class="chapter-item expanded "><a href="types/numeric.html"><strong aria-hidden="true">10.1.2.</strong> 数字型</a></li><li class="chapter-item expanded "><a href="types/textual.html"><strong aria-hidden="true">10.1.3.</strong> 字符型</a></li><li class="chapter-item expanded "><a href="types/never.html"><strong aria-hidden="true">10.1.4.</strong> never类型</a></li><li class="chapter-item expanded "><a href="types/tuple.html"><strong aria-hidden="true">10.1.5.</strong> 元组</a></li><li class="chapter-item expanded "><a href="types/array.html"><strong aria-hidden="true">10.1.6.</strong> 数组</a></li><li class="chapter-item expanded "><a href="types/slice.html"><strong aria-hidden="true">10.1.7.</strong> 切片</a></li><li class="chapter-item expanded "><a href="types/struct.html"><strong aria-hidden="true">10.1.8.</strong> 结构体</a></li><li class="chapter-item expanded "><a href="types/enum.html"><strong aria-hidden="true">10.1.9.</strong> 枚举</a></li><li class="chapter-item expanded "><a href="types/union.html"><strong aria-hidden="true">10.1.10.</strong> 联合体</a></li><li class="chapter-item expanded "><a href="types/function-item.html"><strong aria-hidden="true">10.1.11.</strong> 函数项类型</a></li><li class="chapter-item expanded "><a href="types/closure.html"><strong aria-hidden="true">10.1.12.</strong> 闭包</a></li><li class="chapter-item expanded "><a href="types/pointer.html"><strong aria-hidden="true">10.1.13.</strong> 指针型</a></li><li class="chapter-item expanded "><a href="types/function-pointer.html"><strong aria-hidden="true">10.1.14.</strong> 函数指针</a></li><li class="chapter-item expanded "><a href="types/trait-object.html"><strong aria-hidden="true">10.1.15.</strong> trait对象</a></li><li class="chapter-item expanded "><a href="types/impl-trait.html"><strong aria-hidden="true">10.1.16.</strong> 实现trait</a></li><li class="chapter-item expanded "><a href="types/parameters.html"><strong aria-hidden="true">10.1.17.</strong> 类型参数</a></li><li class="chapter-item expanded "><a href="types/inferred.html"><strong aria-hidden="true">10.1.18.</strong> 推断型</a></li></ol></li><li class="chapter-item expanded "><a href="dynamically-sized-types.html"><strong aria-hidden="true">10.2.</strong> 动态尺寸类型(DST)</a></li><li class="chapter-item expanded "><a href="type-layout.html"><strong aria-hidden="true">10.3.</strong> 类型布局 </a></li><li class="chapter-item expanded "><a href="interior-mutability.html"><strong aria-hidden="true">10.4.</strong> 内部可变性</a></li><li class="chapter-item expanded "><a href="subtyping.html"><strong aria-hidden="true">10.5.</strong> 子类型和型变</a></li><li class="chapter-item expanded "><a href="trait-bounds.html"><strong aria-hidden="true">10.6.</strong> trait约束及其生存期约束</a></li><li class="chapter-item expanded "><a href="type-coercions.html"><strong aria-hidden="true">10.7.</strong> 类型自动强转</a></li><li class="chapter-item expanded "><a href="destructors.html"><strong aria-hidden="true">10.8.</strong> 析构函数</a></li><li class="chapter-item expanded "><a href="lifetime-elision.html"><strong aria-hidden="true">10.9.</strong> 生存期省略</a></li></ol></li><li class="chapter-item expanded "><a href="special-types-and-traits.html"><strong aria-hidden="true">11.</strong> 特殊类型和 trait</a></li><li class="chapter-item expanded "><a href="names.html"><strong aria-hidden="true">12.</strong> 名称</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="names/namespaces.html"><strong aria-hidden="true">12.1.</strong> 命名空间</a></li><li class="chapter-item expanded "><a href="names/scopes.html"><strong aria-hidden="true">12.2.</strong> 作用域</a></li><li class="chapter-item expanded "><a href="names/preludes.html"><strong aria-hidden="true">12.3.</strong> 预导入包</a></li><li class="chapter-item expanded "><a href="paths.html"><strong aria-hidden="true">12.4.</strong> 路径</a></li><li class="chapter-item expanded "><a href="names/name-resolution.html"><strong aria-hidden="true">12.5.</strong> 名称解析</a></li><li class="chapter-item expanded "><a href="visibility-and-privacy.html"><strong aria-hidden="true">12.6.</strong> 可见性与隐私权</a></li></ol></li><li class="chapter-item expanded "><a href="memory-model.html"><strong aria-hidden="true">13.</strong> 内存模型</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="memory-allocation-and-lifetime.html"><strong aria-hidden="true">13.1.</strong> 内存分配和生存期</a></li><li class="chapter-item expanded "><a href="variables.html"><strong aria-hidden="true">13.2.</strong> 变量</a></li></ol></li><li class="chapter-item expanded "><a href="linkage.html"><strong aria-hidden="true">14.</strong> 链接(linkage)</a></li><li class="chapter-item expanded "><a href="unsafety.html"><strong aria-hidden="true">15.</strong> 非安全性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="unsafe-functions.html"><strong aria-hidden="true">15.1.</strong> 非安全函数</a></li><li class="chapter-item expanded "><a href="unsafe-blocks.html"><strong aria-hidden="true">15.2.</strong> 非安全代码块</a></li><li class="chapter-item expanded "><a href="behavior-considered-undefined.html"><strong aria-hidden="true">15.3.</strong> 未定义行为</a></li><li class="chapter-item expanded "><a href="behavior-not-considered-unsafe.html"><strong aria-hidden="true">15.4.</strong> 不被认为是非安全的行为</a></li></ol></li><li class="chapter-item expanded "><a href="const_eval.html"><strong aria-hidden="true">16.</strong> 常量求值</a></li><li class="chapter-item expanded "><a href="abi.html"><strong aria-hidden="true">17.</strong> ABI</a></li><li class="chapter-item expanded "><a href="runtime.html"><strong aria-hidden="true">18.</strong> Rust运行时</a></li><li class="chapter-item expanded "><a href="appendices.html"><strong aria-hidden="true">19.</strong> 附录</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="macro-ambiguity.html" class="active"><strong aria-hidden="true">19.1.</strong> 宏定义规范</a></li><li class="chapter-item expanded "><a href="influences.html"><strong aria-hidden="true">19.2.</strong> 影响来源</a></li><li class="chapter-item expanded "><a href="glossary.html"><strong aria-hidden="true">19.3.</strong> 术语表</a></li><li class="chapter-item expanded "><a href="本书术语翻译对照表.html"><strong aria-hidden="true">19.4.</strong> 本书术语翻译对照表</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                        
                    </div>

                    <h1 class="menu-title"></h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        
                        <a href="https://gitee.com/minstrel1977/rust-reference" title="Git repository" aria-label="Git repository">
                            <i id="git-repository-button" class="fa fa-github"></i>
                        </a>
                        
                    </div>
                </div>

                
                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1><a class="header" href="#appendixmacro-follow-set-ambiguity-formal-specification" id="appendixmacro-follow-set-ambiguity-formal-specification">Appendix：Macro Follow-Set Ambiguity Formal Specification</a></h1>
<h1><a class="header" href="#附录关于宏随集的二义性的形式化规范" id="附录关于宏随集的二义性的形式化规范">附录：关于宏随集的二义性的形式化规范</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/macro-ambiguity.md">macro-ambiguity.md</a><br />
commit:  6ee9fc95ac3b7df8a01079e13280a283a7a24612 <br />
本章译文最后维护日期：2021-07-11</p>
</blockquote>
<p>本文介绍了下述<a href="macros-by-example.html">声明宏</a>规则的正式规范。它们最初是在 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md">RFC 550</a> 中指定的（本文的大部分内容都是从其中复制过来的），并在后续的 RFC 中进行了进一步的展开论述。</p>
<h2><a class="header" href="#definitions--conventions" id="definitions--conventions">Definitions &amp; Conventions</a></h2>
<h2><a class="header" href="#定义和约定" id="定义和约定">定义和约定</a></h2>
<ul>
<li><code>macro</code>：宏，源代码中任何可调用的类似 <code>foo!(...)</code> 的东西。</li>
<li><code>MBE</code>：macro-by-example，声明宏，由 <code>macro_rules</code> 定义的宏。</li>
<li><code>matcher</code>：匹配器，<code>macro_rules</code>调用中一条规则的左侧部分，或其子部分(subportion)。（译者注：子部分的意思是匹配器可嵌套，可相互包含）</li>
<li><code>macro parser</code>：宏解释器，Rust 解析器中的一段程序，这段程序使用从所有命中的匹配器中推导出的文法规则来解析宏输入。</li>
<li><code>fragment</code>：匹配段，给定匹配器将接受（或“匹配”）的 Rust 句法对象。</li>
<li><code>repetition</code> ：重复元，遵循正则重复模式的匹配段。</li>
<li><code>NT</code>：non-terminal，非终结符，可以出现在匹配器中的各种“元变量”或重复元匹配器，在声明宏(MBE)句法中用前导字符 <code>$</code> 标明。</li>
<li><code>simple NT</code>：简单NT，“元变量”类型的非终结符（下面会进一步讨论）。</li>
<li><code>complex NT</code>：复杂NT，重复元类型的非终结符，通过重复元操作符（<code>*</code>, <code>+</code>, <code>?</code>）指定重复次数。 <!-- a repetition matching non-terminal, specified via repetition operators (`*`, `+`, `?`). --></li>
<li><code>token</code>：匹配器中不可再细分的元素；例如，标识符、操作符、开/闭定界符<em>和</em>简单NT(simple NT)。</li>
<li><code>token tree</code>：token树，token树由 token(叶)、复杂NT 和子token树（token树的有限序列）组成的树形数据结构。</li>
<li><code>delimiter token</code>：定界符，一种用于划分一个匹配段的结束和下一个匹配段的开始的 token。</li>
<li><code>separator token</code>：分隔符，复杂NT 中的可选定界符，用在重复元里以分隔元素。</li>
<li><code>separated complex NT</code>：带分隔符的复杂NT，分隔符是重复元的一部分的复杂NT。</li>
<li><code>delimited sequence</code>：有界序列，在序列的开始和结束处使用了适当的开闭定界符的 token树。</li>
<li><code>empty fragment</code>：空匹配段，一种不可见的 Rust 句法对象，它分割各种 token，例如空白符(whitespace)或者（在某些词法上下文中的）空标记序列。</li>
<li><code>fragment specifier</code>：匹配段选择器，简单NT 中的后段标识符部分，指定 NT 接受哪种类型的匹配段。<!-- The identifier in a simple NT that specifies which fragment the NT accepts. tobemodify--></li>
<li><code>language</code>：与上下文无关的语言。</li>
</ul>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! i_am_an_mbe {
    (start $foo:expr $($i:ident),* end) =&gt; ($foo)
}
<span class="boring">}
</span></code></pre></pre>
<p><code>(start $foo:expr $($i:ident),* end)</code> 是一个匹配器(matcher)。整个匹配器是一段有界字符序列（使用开闭定界符 <code>(</code> 和 <code>)</code> 界定），<code>$foo</code> 和 <code>$i</code> 是简单NT(simple NT)， <code>expr</code> 和 <code>ident</code> 是它们各自的匹配段选择器(fragment specifiers)。</p>
<p><code>$(i:ident),*</code> <em>也</em>是一个 NT；它是一个复杂NT，匹配那些被逗号分隔成的标识符类型的重复元。<code>,</code> 是这个复杂NT 的分隔符；它出现在匹配段的每对元素（如果有的话）之间。</p>
<p>复杂NT 的另一个例子是 <code>$(hi $e:expr ;)+</code>，它匹配 <code>hi &lt;expr&gt;; hi &lt;expr&gt;; ...</code> 这种格式的代码，其中 <code>hi &lt;expr&gt;;</code> 至少出现一次。注意，这种复杂NT 没有专用的分隔符。</p>
<p>(请注意，Rust 解析器会确保这类有界字符序列始终具有正确的 token树的嵌套结构以及开/闭定界符的正确匹配。)</p>
<p>下面，我们将用变量“M”表示匹配器，变量“t”和“u”表示任意单一 token，变量“tt”和“uu”表示任意 token树。（使用“tt”确实存在潜在的歧义，因为它的额外角色是一个匹配段选择器；但不用太担心，因为从上下文中，可以很清楚地看出哪个解释更符合语义）</p>
<p>用“SEP”代表分隔符，“OP”代表重复元运算符 <code>*</code>, <code>+</code>, 和 <code>?</code> “OPEN”/“CLOSE”代表包围定界字符序列的 token对（例如 <code>[</code> 和 <code>]</code> ）。</p>
<p>用希腊字母 &quot;α&quot; &quot;β&quot; &quot;γ&quot; &quot;δ&quot; 代表潜在的空token树序列。（注意没有使用希腊字母 &quot;ε&quot;，&quot;ε&quot;(epsilon)在此表示形式中代表一类特殊的角色，不代表 token树序列。）</p>
<ul>
<li>这种希腊字母约定通常只是在需要展现一段字符序列的技术细节时才被引入；特别是，当我们希望<em>强调</em>我们操作的是一个 token树序列时，我们将对该序列使用表义符 &quot;tt ...&quot;，而不是一个希腊字母。</li>
</ul>
<p>请注意，匹配器仅仅是一个 token树。如前所述，“简单NT”是一个元变量类型的 NT；因此，这是一个非重复元。例如，<code>$foo:ty</code> 是一个简单NT，而 <code>$($foo:ty)+</code> 是一个复杂NT。</p>
<p>还请注意，在这种形式体系的上下文中，术语“token”通常<em>包括</em>简单NT。</p>
<p>最后，读者要记住，根据这种形式体系的定义，简单NT 不会匹配空匹配段，因此也没有 token 会匹配 Rust句法的空匹配段。（因此，能够匹配空匹配段的 NT <em>唯有</em>复杂NT。）但这还不是全部事实，因为 <code>vis</code> 匹配器可以匹配空匹配段。因此，为了达到这种形式体系自洽统一的目的，我们将把 <code>$v:vis</code> 看作是 <code>$($v:vis)?</code>，来让匹配器匹配一个空匹配段。</p>
<h3><a class="header" href="#the-matcher-invariants" id="the-matcher-invariants">The Matcher Invariants</a></h3>
<h3><a class="header" href="#匹配器的不变式" id="匹配器的不变式">匹配器的不变式</a></h3>
<p>为了有效，匹配器必须满足以下三个不变式。注意其中 FIRST 和 FOLLOW 的定义将在后面进行描述。</p>
<ol>
<li>对于匹配器 <code>M</code> 中的任意两个连续的 token树序列（即 <code>M = ... tt uu ...</code>），并且 <code>uu ...</code> 非空，必有 FOLLOW(<code>... tt</code>) ∪ {ε} ⊇ FIRST(<code>uu ...</code>)。</li>
<li>对于匹配器中任何带分隔符的复杂NT，<code>M = ... $(tt ...) SEP OP ...</code>，必有 <code>SEP</code> ∈ FOLLOW(<code>tt ...</code>)</li>
<li>对于匹配器中不带分隔符的复杂NT，<code>M = ... $(tt ...) OP ...</code>，如果 OP = <code>*</code> 或 <code>+</code>，必有 FOLLOW(<code>tt ...</code>) ⊇ FIRST(<code>tt ...</code>)。</li>
</ol>
<p>第一个不变式表示，无论匹配器后出现什么 token（如果有的话），它都必须出现在先决随集(predetermined follow set)中的某个地方。这将确保合法的宏定义将继续对 <code>... tt</code> 的结束和 <code>uu ...</code> 的开始执行相同的判定(determination)，即使将来语言中添加了新的句法形式。
The first invariant says that whatever actual token that comes after a matcher, if any, must be somewhere in the predetermined follow set. This ensures that a legal macro definition will continue to assign the same determination as to where <code>... tt</code> ends and <code>uu ...</code> begins, even as new syntactic forms are added to the language.</p>
<p>第二个不变式表示一个带分隔符的复杂NT 必须使用一个分隔符，它是 NT 的内部内容的先决随集的一部分。这将确保合法的宏定义将继续将输入匹配段解析成相同的定界字符序列 <code>tt ...</code>，即使在将来语言中添加了新的语法形式。
The second invariant says that a separated complex NT must use a separator token that is part of the predetermined follow set for the internal contents of the NT. This ensures that a legal macro definition will continue to parse an input fragment into the same delimited sequence of <code>tt ...</code>'s, even as new syntactic forms are added to the language.</p>
<p>第三个不变式说的是，当我们有一个复杂NT，它可以匹配同一字符序列的两个或多个副本，并且两者之间没有分隔符，那么根据第一个不变式，它们必须可以放在一起。这个不变式还要求它们是非空的，这消除了可能出现的歧义。
The third invariant says that when we have a complex NT that can match two or more copies of the same thing with no separation in between, it must be permissible for them to be placed next to each other as per the first invariant. This invariant also requires they be nonempty, which eliminates a possible ambiguity.</p>
<p><strong>注意：由于历史疏忽和对行为的严重依赖，第三个不变式目前没有被执行。目前还没有决定下一步该怎么做。不遵循这个不变式的宏可能会在未来的 Rust版本中失效。参见<a href="https://github.com/rust-lang/rust/issues/56575">跟踪问题</a></strong>
<strong>NOTE：The third invariant is currently unenforced due to historical oversight and significant reliance on the behaviour. It is currently undecided what to do about this going forward. Macros that do not respect the behaviour may become invalid in a future edition of Rust. See the <a href="https://github.com/rust-lang/rust/issues/56575">tracking issue</a>.</strong></p>
<h3><a class="header" href="#first-and-follow-informally" id="first-and-follow-informally">FIRST and FOLLOW, informally</a></h3>
<h3><a class="header" href="#非正式的-first集合和-follow集合定义" id="非正式的-first集合和-follow集合定义">非正式的 FIRST集合和 FOLLOW集合定义</a></h3>
<p>给定匹配器 M 映射到三个集合：FIRST(M)，LAST(M) 和 FOLLOW(M)。
A given matcher M maps to three sets：FIRST(M), LAST(M) and FOLLOW(M).</p>
<p>这三个集合中的每一个都是由一组 token 组成的。FIRST(M) 和 LAST(M) 也可能包含一个可区分的非token元素 ε (&quot;epsilon&quot;)，这表示 M 可以匹配空匹配段。（但是 FOLLOW(M) 始终只是一组 token。）
Each of the three sets is made up of tokens. FIRST(M) and LAST(M) may also contain a distinguished non-token element ε (&quot;epsilon&quot;), which indicates that M can match the empty fragment. (But FOLLOW(M) is always just a set of tokens.)</p>
<p>非正式定义(Informally)：</p>
<ul>
<li>
<p>FIRST(M)：收集匹配段与 M 匹配时可能首先使用的 token。collects the tokens potentially used first when matching a fragment to M.</p>
</li>
<li>
<p>LAST(M)：收集匹配段与 M 匹配时可能最后使用的 token。collects the tokens potentially used last when matching a fragment to M.</p>
</li>
<li>
<p>FOLLOW(M)：允许紧跟在由 M 匹配的某个匹配段之后的 token集合。the set of tokens allowed to follow immediately after some fragment matched by M.</p>
<p>换言之：t ∈ FOLLOW(M) 当且仅当存在（可能为空的）token序列 α、β、γ、δ，其中：</p>
<ul>
<li>M 匹配 β，</li>
<li>t 与 γ 匹配，并且</li>
<li>连结 α β γ δ 是一段可解析的 Rust程序。
In other words：t ∈ FOLLOW(M) if and only if there exists (potentially empty) token sequences α, β, γ, δ where:</li>
<li>M matches β,</li>
<li>t matches γ, and</li>
<li>The concatenation α β γ δ is a parseable Rust program.</li>
</ul>
</li>
</ul>
<p>我们使用简写的 ANYTOKEN 来表示所有 token（包括简单NT）的集合。例如，如果任何 token 在匹配器 M 之后都是合法的，那么 FOLLOW(M) = ANYTOKEN。
We use the shorthand ANYTOKEN to denote the set of all tokens (including simple NTs). For example, if any token is legal after a matcher M, then FOLLOW(M) = ANYTOKEN.</p>
<p>（为了加深对上述非正式定义描述的理解，读者在阅读正式定义之前，可以先在这里读一遍后面 [关于 FIRST 和 LAST 的示例](#examples-of FIRST -and- LAST)。）
(To review one's understanding of the above informal descriptions, the reader at this point may want to jump ahead to the <a href="#examples-of-first-and-last">examples of FIRST/LAST</a> before reading their formal definitions.)</p>
<h3><a class="header" href="#first-last" id="first-last">FIRST, LAST</a></h3>
<p>下面是对 FIRST 和 LAST 的正式归纳定义(formal inductive definitions)。</p>
<p>“A∪B”表示集合并集，“A∩B”表示集合交集，“A\B”表示集合差集（即存在于A中，且不存在于B中的所有元素的集合）。</p>
<h4><a class="header" href="#first" id="first">FIRST</a></h4>
<p>FIRST(M) 是通过对序列 M 及其第一个 token树(如果有的话)的结构进行案例分析来定义的:
FIRST(M) is defined by case analysis on the sequence M and the structure of its first token-tree (if any):</p>
<ul>
<li>
<p>如果 M 为空序列，则 FIRST(M) = { ε }，if M is the empty sequence, then FIRST(M) = { ε },</p>
</li>
<li>
<p>如果 M 以 token t 开始，则 FIRST(M) = { t }，if M starts with a token t, then FIRST(M) = { t },</p>
<p>（注意:这涵盖了这样一种情况：M 以一个定界的token树序列开始，<code>M = OPEN tt ... CLOSE ...</code>，此时 <code>t = OPEN</code>，因此 FIRST(M) = { <code>OPEN</code> }。）
(Note：this covers the case where M starts with a delimited token-tree sequence, <code>M = OPEN tt ... CLOSE ...</code>, in which case <code>t = OPEN</code> and thus FIRST(M) = { <code>OPEN</code> }.)</p>
<p>（注意：这主要依赖于没有简单NT与空匹配段匹配这一特性。）
(Note：this critically relies on the property that no simple NT matches the empty fragment.)</p>
</li>
<li>
<p>否则，M 是一个以复杂NT开始的token树序列：<code>M = $( tt ... ) OP α</code>，或 <code>M = $( tt ... ) SEP OP α</code>，(其中 <code>α</code> 是匹配器其余部分的token树序列(可能是空的))。Otherwise, M is a token-tree sequence starting with a complex NT：<code>M = $( tt ... ) OP α</code>, or <code>M = $( tt ... ) SEP OP α</code>, (where <code>α</code> is the (potentially empty) sequence of token trees for the rest of the matcher).</p>
<ul>
<li>Let SEP_SET(M) = { SEP } 如果存在 SEP 且 ε ∈ FIRST(<code>tt ...</code>)；否则 SEP_SET(M) = {}。</li>
</ul>
</li>
<li>
<p>Let ALPHA_SET(M) = FIRST(<code>α</code>) if OP = <code>*</code> or <code>?</code> and ALPHA_SET(M) = {} if OP = <code>+</code>.</p>
</li>
<li>
<p>FIRST(M) = (FIRST(<code>tt ...</code>) \ {ε}) ∪ SEP_SET(M) ∪ ALPHA_SET(M).</p>
</li>
</ul>
<p>复杂NT 的定义值得商榷。SEP_SET(M) 定义了分隔符可能是 M 的第一个有效token的可能性，当定义了分隔符且重复匹配段可能为空时，就会发生这种情况。ALPHA_SET(M)定义了复杂NT可能为空的可能性，这意味着 M 的第一个有效token集合是后继token树序列 <code>α</code> 。当使用了操作符 <code>*</code> 或 <code>?</code> 时，这种情况下可能没有重复元。理论上，如果 <code>+</code> 与一个可能为空的重复匹配段一起使用，也会出现这种情况，但是第三个不变式禁止这样做。
The definition for complex NTs deserves some justification. SEP_SET(M) defines the possibility that the separator could be a valid first token for M, which happens when there is a separator defined and the repeated fragment could be empty. ALPHA_SET(M) defines the possibility that the complex NT could be empty, meaning that M's valid first tokens are those of the following token-tree sequences <code>α</code>. This occurs when either <code>*</code> or <code>?</code> is used, in which case there could be zero repetitions. In theory, this could also occur if <code>+</code> was used with a potentially-empty repeating fragment, but this is forbidden by the third invariant.</p>
<p>From there, clearly FIRST(M) can include any token from SEP_SET(M) or ALPHA_SET(M), and if the complex NT match is nonempty, then any token starting FIRST(<code>tt ...</code>) could work too. The last piece to consider is ε. SEP_SET(M) and FIRST(<code>tt ...</code>) \ {ε} cannot contain ε, but ALPHA_SET(M) could. Hence, this definition allows M to accept ε if and only if ε ∈ ALPHA_SET(M) does. This is correct because for M to accept ε in the complex NT case, both the complex NT and α must accept it. If OP = <code>+</code>, meaning that the complex NT cannot be empty, then by definition ε ∉ ALPHA_SET(M). Otherwise, the complex NT can accept zero repetitions, and then ALPHA_SET(M) = FOLLOW(<code>α</code>). So this definition is correct with respect to \varepsilon as well.</p>
<h4><a class="header" href="#last" id="last">LAST</a></h4>
<p>LAST(M), defined by case analysis on M itself (a sequence of token-trees):</p>
<ul>
<li>
<p>if M is the empty sequence, then LAST(M) = { ε }</p>
</li>
<li>
<p>if M is a singleton token t, then LAST(M) = { t }</p>
</li>
<li>
<p>if M is the singleton complex NT repeating zero or more times, <code>M = $( tt ... ) *</code>, or <code>M = $( tt ... ) SEP *</code></p>
<ul>
<li>
<p>Let sep_set = { SEP } if SEP present; otherwise sep_set = {}.</p>
</li>
<li>
<p>if ε ∈ LAST(<code>tt ...</code>) then LAST(M) = LAST(<code>tt ...</code>) ∪ sep_set</p>
</li>
<li>
<p>otherwise, the sequence <code>tt ...</code> must be non-empty; LAST(M) = LAST(<code>tt ...</code>) ∪ {ε}.</p>
</li>
</ul>
</li>
<li>
<p>if M is the singleton complex NT repeating one or more times, <code>M = $( tt ... ) +</code>, or <code>M = $( tt ... ) SEP +</code></p>
<ul>
<li>
<p>Let sep_set = { SEP } if SEP present; otherwise sep_set = {}.</p>
</li>
<li>
<p>if ε ∈ LAST(<code>tt ...</code>) then LAST(M) = LAST(<code>tt ...</code>) ∪ sep_set</p>
</li>
<li>
<p>otherwise, the sequence <code>tt ...</code> must be non-empty; LAST(M) = LAST(<code>tt ...</code>)</p>
</li>
</ul>
</li>
<li>
<p>if M is the singleton complex NT repeating zero or one time, <code>M = $( tt ...) ?</code>, then LAST(M) = LAST(<code>tt ...</code>) ∪ {ε}.</p>
</li>
<li>
<p>if M is a delimited token-tree sequence <code>OPEN tt ... CLOSE</code>, then LAST(M) =
{ <code>CLOSE</code> }.</p>
</li>
<li>
<p>if M is a non-empty sequence of token-trees <code>tt uu ...</code>,</p>
<ul>
<li>
<p>If ε ∈ LAST(<code>uu ...</code>), then LAST(M) = LAST(<code>tt</code>) ∪ (LAST(<code>uu ...</code>) \ { ε }).</p>
</li>
<li>
<p>Otherwise, the sequence <code>uu ...</code> must be non-empty; then LAST(M) =
LAST(<code>uu ...</code>).</p>
</li>
</ul>
</li>
</ul>
<h3><a class="header" href="#examples-of-first-and-last" id="examples-of-first-and-last">Examples of FIRST and LAST</a></h3>
<h3><a class="header" href="#关于-first-和-last-的示例" id="关于-first-和-last-的示例">关于 FIRST 和 LAST 的示例</a></h3>
<p>下面是一些关于 FIRST 和 LAST 的例子。（请特别注意，特殊元素 ε 是如何根据输入匹配段之间的相互作用来引入和消除的。）
Below are some examples of FIRST and LAST. (Note in particular how the special ε element is introduced and eliminated based on the interaction between the pieces of the input.)</p>
<p>我们的第一个例子以树状结构呈现，以详细说明匹配器的分析是如何组成的。（一些较简单的子树已被删除。）
Our first example is presented in a tree structure to elaborate on how the analysis of the matcher composes. (Some of the simpler subtrees have been elided.)</p>
<pre><code class="language-text">INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+   g
            ~~~~~~~~   ~~~~~~~                ~
                |         |                   |
FIRST：  { $d:ident }  { $e:expr }          { h }


INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+
            ~~~~~~~~~~~~~~~~~~             ~~~~~~~           ~~~
                        |                      |               |
FIRST：         { $d:ident }               { h, ε }         { f }

INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+   g
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~    ~~~~~~~~~~~~~~    ~~~~~~~~~   ~
                        |                       |              |       |
FIRST：       { $d:ident, ε }            {  h, ε, ;  }      { f }   { g }


INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+   g
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                        |
FIRST：                      { $d:ident, h, ;,  f }
</code></pre>
<p>Thus:</p>
<ul>
<li>FIRST(<code>$($d:ident $e:expr );* $( $(h)* );* $( f ;)+ g</code>) = { <code>$d:ident</code>, <code>h</code>, <code>;</code>, <code>f</code> }</li>
</ul>
<p>Note however that:</p>
<ul>
<li>FIRST(<code>$($d:ident $e:expr );* $( $(h)* );* $($( f ;)+ g)*</code>) = { <code>$d:ident</code>, <code>h</code>, <code>;</code>, <code>f</code>, ε }</li>
</ul>
<p>Here are similar examples but now for LAST.</p>
<ul>
<li>LAST(<code>$d:ident $e:expr</code>) = { <code>$e:expr</code> }</li>
<li>LAST(<code>$( $d:ident $e:expr );*</code>) = { <code>$e:expr</code>, ε }</li>
<li>LAST(<code>$( $d:ident $e:expr );* $(h)*</code>) = { <code>$e:expr</code>, ε, <code>h</code> }</li>
<li>LAST(<code>$( $d:ident $e:expr );* $(h)* $( f ;)+</code>) = { <code>;</code> }</li>
<li>LAST(<code>$( $d:ident $e:expr );* $(h)* $( f ;)+ g</code>) = { <code>g</code> }</li>
</ul>
<h3><a class="header" href="#followm" id="followm">FOLLOW(M)</a></h3>
<p>Finally, the definition for FOLLOW(M) is built up as follows. pat, expr, etc.
represent simple nonterminals with the given fragment specifier.</p>
<ul>
<li>
<p>FOLLOW(pat) = {<code>=&gt;</code>, <code>,</code>, <code>=</code>, <code>|</code>, <code>if</code>, <code>in</code>}`.</p>
</li>
<li>
<p>FOLLOW(expr) = FOLLOW(stmt) =  {<code>=&gt;</code>, <code>,</code>, <code>;</code>}`.</p>
</li>
<li>
<p>FOLLOW(ty) = FOLLOW(path) = {<code>{</code>, <code>[</code>, <code>,</code>, <code>=&gt;</code>, <code>:</code>, <code>=</code>, <code>&gt;</code>, <code>&gt;&gt;</code>, <code>;</code>,
<code>|</code>, <code>as</code>, <code>where</code>, block nonterminals}.</p>
</li>
<li>
<p>FOLLOW(vis) = {<code>,</code>l any keyword or identifier except a non-raw <code>priv</code>; any
token that can begin a type; ident, ty, and path nonterminals}.</p>
</li>
<li>
<p>FOLLOW(t) = ANYTOKEN for any other simple token, including block, ident,
tt, item, lifetime, literal and meta simple nonterminals, and all terminals.</p>
</li>
<li>
<p>FOLLOW(M), for any other M, is defined as the intersection, as t ranges over
(LAST(M) \ {ε}), of FOLLOW(t).</p>
</li>
</ul>
<p>The tokens that can begin a type are, as of this writing, {<code>(</code>, <code>[</code>, <code>!</code>, <code>*</code>,
<code>&amp;</code>, <code>&amp;&amp;</code>, <code>?</code>, lifetimes, <code>&gt;</code>, <code>&gt;&gt;</code>, <code>::</code>, any non-keyword identifier, <code>super</code>,
<code>self</code>, <code>Self</code>, <code>extern</code>, <code>crate</code>, <code>$crate</code>, <code>_</code>, <code>for</code>, <code>impl</code>, <code>fn</code>, <code>unsafe</code>,
<code>typeof</code>, <code>dyn</code>}, although this list may not be complete because people won't
always remember to update the appendix when new ones are added.</p>
<p>Examples of FOLLOW for complex M:</p>
<ul>
<li>FOLLOW(<code>$( $d:ident $e:expr )*</code>) = FOLLOW(<code>$e:expr</code>)</li>
<li>FOLLOW(<code>$( $d:ident $e:expr )* $(;)*</code>) = FOLLOW(<code>$e:expr</code>) ∩ ANYTOKEN = FOLLOW(<code>$e:expr</code>)</li>
<li>FOLLOW(<code>$( $d:ident $e:expr )* $(;)* $( f |)+</code>) = ANYTOKEN</li>
</ul>
<h3><a class="header" href="#examples-of-valid-and-invalid-matchers" id="examples-of-valid-and-invalid-matchers">Examples of valid and invalid matchers</a></h3>
<p>With the above specification in hand, we can present arguments for
why particular matchers are legal and others are not.</p>
<ul>
<li>
<p><code>($ty:ty &lt; foo ,)</code> ：illegal, because FIRST(<code>&lt; foo ,</code>) = { <code>&lt;</code> } ⊈ FOLLOW(<code>ty</code>)</p>
</li>
<li>
<p><code>($ty:ty , foo &lt;)</code> ：legal, because FIRST(<code>, foo &lt;</code>) = { <code>,</code> }  is ⊆ FOLLOW(<code>ty</code>).</p>
</li>
<li>
<p><code>($pa:pat $pb:pat $ty:ty ,)</code> ：illegal, because FIRST(<code>$pb:pat $ty:ty ,</code>) = { <code>$pb:pat</code> } ⊈ FOLLOW(<code>pat</code>), and also FIRST(<code>$ty:ty ,</code>) = { <code>$ty:ty</code> } ⊈ FOLLOW(<code>pat</code>).</p>
</li>
<li>
<p><code>( $($a:tt $b:tt)* ; )</code> ：legal, because FIRST(<code>$b:tt</code>) = { <code>$b:tt</code> } is ⊆ FOLLOW(<code>tt</code>) = ANYTOKEN, as is FIRST(<code>;</code>) = { <code>;</code> }.</p>
</li>
<li>
<p><code>( $($t:tt),* , $(t:tt),* )</code> ：legal,  (though any attempt to actually use this macro will signal a local ambiguity error during expansion).</p>
</li>
<li>
<p><code>($ty:ty $(; not sep)* -)</code> ：illegal, because FIRST(<code>$(; not sep)* -</code>) = { <code>;</code>, <code>-</code> } is not in FOLLOW(<code>ty</code>).</p>
</li>
<li>
<p><code>($($ty:ty)-+)</code> ：illegal, because separator <code>-</code> is not in FOLLOW(<code>ty</code>).</p>
</li>
<li>
<p><code>($($e:expr)*)</code> ：illegal, because expr NTs are not in FOLLOW(expr NT).</p>
</li>
</ul>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        
                            <a rel="prev" href="appendices.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                        

                        
                            <a rel="next" href="influences.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                
                    <a rel="prev" href="appendices.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a rel="next" href="influences.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
                
            </nav>

        </div>

        

        

        

        
        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        

        

        
        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
        

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

        

    </body>
</html>
